﻿using System;
using Controls = System.Windows.Controls;

// these interfaces are here to provide a generic implementation that works for all platforms
// including Silverlight, Windows Desktop, and Web

namespace UIObjects.DragDropInterfaces
{
    public class GiveFeedbackEventArgs : EventArgs
    {
        // Summary:
        //     Gets a value that indicates the effects of drag-and-drop operation.
        public DragDropEffects Effects { get; set;  }

        /// <summary>
        /// Gets or sets a value indicating whether the present state of the 
        /// event handling for a routed event as it travels the route.
        /// </summary>
        public bool Handled { get; set; }

        /// <summary>
        /// Gets the original reporting source as determined by pure hit testing, before
        /// any possible System.Windows.RoutedEventArgs.Source adjustment by a parent
        /// class.
        /// </summary>
        public object OriginalSource { get; set; }

        public GiveFeedbackEventArgs(DragDropEffects effects)
        {
            this.Effects = effects;
        }
    }

    // Summary:
    //     Specifies the current state of the modifier keys (SHIFT, CTRL, and ALT),
    //     as well as the state of the mouse buttons.
    [Flags]
    public enum DragDropKeyStates
    {
        // Summary:
        //     No modifier keys or mouse buttons are pressed.
        None = 0,
        //
        // Summary:
        //     The left mouse button is pressed.
        LeftMouseButton = 1,
        //
        // Summary:
        //     The right mouse button is pressed.
        RightMouseButton = 2,
        //
        // Summary:
        //     The shift (SHIFT) key is pressed.
        ShiftKey = 4,
        //
        // Summary:
        //     The control (CTRL) key is pressed.
        ControlKey = 8,
        //
        // Summary:
        //     The middle mouse button is pressed.
        MiddleMouseButton = 16,
        //
        // Summary:
        //     The ALT key is pressed.
        AltKey = 32,
    }

    public class ItemDragEventArgs : EventArgs
    {
        // Summary:
        //     Gets or sets the allowed effects.
        public DragDropEffects AllowedEffects { get; set; }
        //
        // Summary:
        //     Gets or sets a value indicating whether to cancel the action.
        public bool Cancel { get; set; }
        //
        // Summary:
        //     Gets or sets the data associated with the item container being dragged.
        public object Data { get; set; }
        //
        // Summary:
        //     Gets a value indicating whether removing data from the source is handled
        //     by the target.
        public bool DataRemovedFromDragSource { get; set; }
        //
        // Summary:
        //     Gets or sets the control that is the source of the drag.
        public object DragSource { get; set; }
        //
        // Summary:
        //     Gets or sets the effects of the completed drag operation.
        public DragDropEffects Effects { get; set; }
        //
        // Summary:
        //     Gets or sets a value indicating whether an item drag operation was handled.
        public bool Handled { get; set; }
        //
        // Summary:
        //     Gets the key states.
        public DragDropKeyStates KeyStates { get; set; }

        public ItemDragEventArgs()
        {
        }
    }

    public class DragEventArgs
    {
        /// <summary>
        /// Gets or sets a value indicating whether the present state of the 
        /// event handling for a routed event as it travels the route.
        /// </summary>
        public bool Handled { get; set; }

        /// <summary>
        /// Gets the original reporting source as determined by pure hit testing, before
        /// any possible System.Windows.RoutedEventArgs.Source adjustment by a parent
        /// class.
        /// </summary>
        public object OriginalSource { get; set; }

        // Summary:
        //     Gets a member of the System.Windows.DragDropEffects enumeration that specifies
        //     which operations are allowed by the originator of the drag event.
        public DragDropEffects AllowedEffects { get; set; }
        //
        // Summary:
        //     Gets a data object that contains the data associated with the corresponding
        //     drag event.
        public object Data { get; set; }
        //
        // Summary:
        //     Gets or sets the target drop-and-drop operation.
        public DragDropEffects Effects { get; set; }
    }

    namespace Extensions
    {
        public static class DragDropExtensions
        {
            public static DragDropInterfaces.ItemDragEventArgs Convert(this System.Windows.Controls.ItemDragEventArgs e)
            {
                var eventArgs = new DragDropInterfaces.ItemDragEventArgs
                {
                    AllowedEffects = (DragDropInterfaces.DragDropEffects) e.AllowedEffects,
                    Cancel = e.Cancel,
                    Data = e.Data,
                    DataRemovedFromDragSource = e.DataRemovedFromDragSource,
                    DragSource = e.DragSource,
                    Effects = (DragDropInterfaces.DragDropEffects) e.Effects,
                    Handled = e.Handled,
                    KeyStates = (DragDropInterfaces.DragDropKeyStates) e.KeyStates
                };

                return eventArgs;
            }

            public static DragDropInterfaces.DragEventArgs Convert(this Microsoft.Windows.DragEventArgs e)
            {
                var eventArgs = new DragDropInterfaces.DragEventArgs
                {
                    AllowedEffects = (DragDropInterfaces.DragDropEffects)e.AllowedEffects,
                    Data = e.Data,
                    Effects = (DragDropInterfaces.DragDropEffects)e.Effects,
                    OriginalSource = e.OriginalSource,
                    Handled = e.Handled
                };

                return eventArgs;
            }

            public static DragDropInterfaces.GiveFeedbackEventArgs Convert(this Microsoft.Windows.GiveFeedbackEventArgs e)
            {
                var eventArgs = new DragDropInterfaces.GiveFeedbackEventArgs((DragDropInterfaces.DragDropEffects)e.Effects);

                eventArgs.Handled = e.Handled;
                eventArgs.OriginalSource = e.OriginalSource;

                return eventArgs;
            }

            public static void ConvertBack(this Controls.ItemDragEventArgs e, DragDropInterfaces.ItemDragEventArgs eventArgs)
            {
                e.AllowedEffects = (Microsoft.Windows.DragDropEffects) eventArgs.AllowedEffects;
                e.Cancel = eventArgs.Cancel;
                e.Data = eventArgs.Data;
                e.Effects = (Microsoft.Windows.DragDropEffects) eventArgs.Effects;
                e.Handled = eventArgs.Handled;
            }

            public static void ConvertBack(this Microsoft.Windows.DragEventArgs e, DragDropInterfaces.DragEventArgs eventArgs)
            {
                e.Effects = (Microsoft.Windows.DragDropEffects)eventArgs.Effects;
                e.Handled = eventArgs.Handled;
            }

            public static void ConvertBack(this Microsoft.Windows.GiveFeedbackEventArgs e, DragDropInterfaces.GiveFeedbackEventArgs eventArgs)
            {
                e.Handled = eventArgs.Handled;
            }
        }
    }

    public interface IDragDrop
    {
        void DragStarting(object sender, ItemDragEventArgs e);
        void DragCompleted(object sender, ItemDragEventArgs e);
        void ItemDropped(object sender, UIObjects.DragDropInterfaces.ItemDragEventArgs e, int insertionIndex);
        void GiveFeedback(object sender, GiveFeedbackEventArgs e);
    }

    [Flags]
    public enum DragDropEffects
    {
        // Summary:
        //     Scrolling is about to start or is currently occurring in the drop target.
        Scroll = -2147483648,
        //
        // Summary:
        //     The data is copied, removed from the drag source, and scrolled in the drop
        //     target.
        All = -2147483645,
        //
        // Summary:
        //     The drop target does not accept the data.
        None = 0,
        //
        // Summary:
        //     The data is copied to the drop target.
        Copy = 1,
        //
        // Summary:
        //     The data from the drag source is moved to the drop target.
        Move = 2,
        //
        // Summary:
        //     The data from the drag source is linked to the drop target.
        Link = 4,
    }
}
